{***************************************************************************}
{                                                                           }
{           Spring Framework for Delphi                                     }
{                                                                           }
{           Copyright (C) 2009-2011 DevJET                                  }
{                                                                           }
{           http://www.spring4d.org                                         }
{                                                                           }
{***************************************************************************}
{                                                                           }
{  Licensed under the Apache License, Version 2.0 (the "License");          }
{  you may not use this file except in compliance with the License.         }
{  You may obtain a copy of the License at                                  }
{                                                                           }
{      http://www.apache.org/licenses/LICENSE-2.0                           }
{                                                                           }
{  Unless required by applicable law or agreed to in writing, software      }
{  distributed under the License is distributed on an "AS IS" BASIS,        }
{  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
{  See the License for the specific language governing permissions and      }
{  limitations under the License.                                           }
{                                                                           }
{***************************************************************************}

unit Spring.Serialization.Backend.NativeXml;

{$I Spring.inc}

interface
uses
  NativeXml,
  Classes,
  SysUtils,
  Rtti,
  Generics.Collections,
  Variants,
  Spring,
  Spring.Collections,
  Spring.Serialization.Backend;

type
  TXmlBackend_NativeXml = class(TBackendBase, IBackend, IInterface)
  protected
    procedure ContentToTree(const stream: TStream; const document: IBackendDocument); override;
    procedure TreeToContent(const stream: TStream; const document: IBackendDocument); override;

    procedure LoadFromStream(const stream: TStream; const document: TNativeXml); virtual;
    procedure SaveToStream(const stream: TStream; const document: TNativeXml); virtual;
  end;

implementation

uses
  Spring.Serialization,
  Spring.Serialization.ResourceStrings;

{ TXmlBackend_TXmlDocument }

procedure TXmlBackend_NativeXml.LoadFromStream(const stream: TStream;
  const document: TNativeXml);
begin
  document.LoadFromStream(stream);
end;

procedure TXmlBackend_NativeXml.SaveToStream(const stream: TStream;
  const document: TNativeXml);
begin
  document.SaveToStream(stream);
end;

procedure TXmlBackend_NativeXml.TreeToContent(const stream: TStream;
  const document: IBackendDocument);

  procedure NodeToXmlNode(const node: IBackendNode; const xmlNode: TXmlNode);
  var
    attributeName: string;
    child: IBackendNode;
  begin
    for attributeName in node.Attributes.Keys do
      xmlNode.AttributeAdd(attributeName, node.Attributes.Items[attributeName]);

    if node.Children.IsEmpty then
      if node.NodeValue <> '' then
        xmlNode.Value := node.NodeValue
      else
    else
      for child in node.Children do
        NodeToXmlNode(child, xmlNode.NodeNew(child.NodeName));
  end;

var
  fNativeXml: TNativeXml;
begin
  fNativeXml := TNativeXml.CreateName(document.Root.NodeName);
  fNativeXml.XmlFormat := xfReadable;
  NodeToXmlNode(document.Root, fNativeXml.Root);
  SaveToStream(stream, fNativeXml);
  fNativeXml.Free;
end;

procedure TXmlBackend_NativeXml.ContentToTree(const stream: TStream;
  const document: IBackendDocument);

  procedure XmlNodeToNode(const xmlNode: TXmlNode; const node: IBackendNode);
  var
    i: integer;
  begin
    node.NodeName := xmlNode.Name;

    for i := 0 to xmlNode.AttributeCount - 1 do
      node.Attributes.AddOrSetValue(xmlNode.Attributes[I].Name,
        xmlNode.Attributes[I].Value);

    if xmlNode.NodeCount = 0 then
      if xmlNode.Value <> null then
        node.NodeValue := xmlNode.Value
      else
    else
      for i := 0 to xmlNode.NodeCount - 1 do
        if xmlNode.Nodes[I].ElementType = NativeXml.xeElement then
          XmlNodeToNode(xmlNode.Nodes[I], node.AddChild);
  end;

var
  fNativeXml: TNativeXml;
begin
  document.Root.Clear;
  try
    fNativeXml := TNativeXml.Create(nil);
    LoadFromStream(stream, fNativeXml);
  except
    raise ESerializationSourceCodeException.CreateRes(@SCodeNotFound);
  end;
  XmlNodeToNode(fNativeXml.Root, document.Root);
  fNativeXml.Free;
end;

end.
